package datagraphics;

import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.*;

import database.*;

/**
 * Manejo de las representaciones gráficas de las preguntas por pantalla.
 * 
 * @author Grupo 11 de Programacion Orientada a Objetos
 * 
 */

public class QuestionVisitor implements Visitor {
	private JPanel jpanel;

	public QuestionVisitor(JPanel jpanel) {
		super();
		this.jpanel = jpanel;
	}

	/**
	 * Renderea una pregunta de tipo MultipleQuestion en pantalla y establece su
	 * comportamiento e interacción con el usuario
	 * 
	 * @param question
	 *            - pregunta de opciones multiples.
	 */

	public void visit(final MultipleQuestion question) {
		ButtonGroup bgroup = new ButtonGroup();
		int cantopt = question.getOptions().length;
		int cantans = question.getCorrectCount();

		if (cantans > 1) {
			JCheckBox[] checks = (JCheckBox[]) renderChecks(question, cantopt);

			for (JCheckBox check : checks) {

				jpanel.add(check);
			}

		} else {
			JRadioButton[] radios = (JRadioButton[]) renderOpts(question,
					cantopt);

			for (JRadioButton radio : radios) {

				bgroup.add(radio);
				jpanel.add(radio);
			}

		}
		jpanel.validate();
	}

	/**
	 * Rendera los CheckBox en pantalla. Ocurre cuando la pregunta tiene más de
	 * 1 respuesta correcta.
	 * 
	 * @param q
	 *            - Obtiene el texto de cada Checkbox según las diferentes
	 *            opciones de la pregunta
	 * @param cantOpts
	 *            - cantidad de opciones de la pregunta
	 */

	private Object[] renderChecks(final MultipleQuestion q, int cantOpts) {
		String[] stropt = q.getOptions();
		final JCheckBox[] checks = new JCheckBox[cantOpts];

		for (int i = 0; i < cantOpts; i++) {
			checks[i] = new JCheckBox("<HTML>" + stropt[i] + "</HTML>");
			checks[i].setActionCommand(String.valueOf(i));

			checks[i].addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent evt) {
					checkActionPerformed(evt, q, checks);
				}
			});
		}

		return checks;
	}

	/**
	 * Renderea las OptionBox para una pregunta de opción múltiple, esto ocurre
	 * cundo de entre las distintas opciones, solo 1 es correcta.
	 * 
	 * @param q
	 *            - pregunta de donde se extraen las opciones posibles
	 * @param cantOpts
	 *            - cantidad de opciones posibles de la pregunta
	 */

	private Object[] renderOpts(final MultipleQuestion q, int cantOpts) {
		String[] stropt = q.getOptions();
		final JRadioButton[] radios = new JRadioButton[cantOpts];

		for (int i = 0; i < cantOpts; i++) {
			radios[i] = new JRadioButton("<HTML>" + stropt[i] + "</HTML>");
			radios[i].setActionCommand(String.valueOf(i));

			radios[i].addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent evt) {
					radioActionPerformed(evt, q, radios);
				}
			});
		}

		return radios;
	}

	/**
	 * Define el comportamiento que ocurre al seleccionarse una CheckBox.
	 * 
	 * @param evt
	 *            - Evento producido por el usuario
	 * @param q
	 *            - Pregunta sobre la cual ocurre el evento.
	 * @param checks
	 *            - CheckBoxes, usados para verificar el estado de la pregunta
	 *            en pantalla (Opciones elegidas como respuestas).
	 */

	private void checkActionPerformed(ActionEvent evt, MultipleQuestion q,
			JCheckBox[] checks) {
		int cantoptions = q.getOptions().length;
		Integer[] ans = new Integer[cantoptions];

		for (int i = 0; i < cantoptions; i++) {
			if (checks[i].isSelected()) {
				ans[i] = 1;
			} else {
				ans[i] = 0;
			}
		}

		q.setUsrAns(ans);
	}

	/**
	 * Define el comportamiento que ocurre cuando el usuario responde a una
	 * pregunta de tipo MultipleQuestion con una única respuesta correcta.
	 * 
	 * @param evt
	 *            - Evento producido por el usuario.
	 * @param q
	 *            - Pregunta sobre la cual se genera el evento
	 * @pram radios - RadioButtons - Usados para verificar el estado de la
	 *       pregunta (Opción elegida como respuesta).
	 */

	private void radioActionPerformed(ActionEvent evt, MultipleQuestion q,
			JRadioButton[] radios) {
		int cantoptions = q.getOptions().length;
		Integer[] ans = new Integer[cantoptions];

		for (int i = 0; i < cantoptions; i++) {
			if (radios[i].isSelected()) {
				ans[i] = 1;
			} else {
				ans[i] = 0;
			}
		}

		q.setUsrAns(ans);

	}

	/**
	 * Renderea una pregunta de tipo BooleanQuestion en pantalla y establece su
	 * comportamiento e interacción con el usuario
	 * 
	 * @param question
	 *            - pregunta de verdadero o falso.
	 */

	public void visit(final BooleanQuestion question) {
		ButtonGroup bgroup = new ButtonGroup();
		JRadioButton rbtrue = new JRadioButton("Verdadero");
		JRadioButton rbfalse = new JRadioButton("Falso");

		rbtrue.setActionCommand("Verdadero");
		rbfalse.setActionCommand("Falso");

		/*
		 * Registra un manejador de eventos para el radio button que elije como
		 * respuesta, la opcion "verdadero"
		 */

		rbtrue.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				rbtrueActionPerformed(evt, question);
			}
		});

		/*
		 * Registra un manejador de eventos para el radio button que elije como
		 * respuesta, la opcion "falso"
		 */

		rbfalse.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				rbfalseActionPerformed(evt, question);
			}
		});
		bgroup.add(rbtrue);
		bgroup.add(rbfalse);

		jpanel.add(rbtrue);
		jpanel.add(rbfalse);
		jpanel.validate();
	}

	/**
	 * Define el comportamiento cuando el usuario interactua con los componentes
	 * gráficos de una BooleanQuestion, en particular, el RadioButton que
	 * representa la respuesta "verdadero".
	 * 
	 * @param evt
	 *            - Evento producido por el usuario
	 * @param question
	 *            - Pregunta sobre la cual ocurre el evento.
	 */

	private void rbtrueActionPerformed(ActionEvent evt, BooleanQuestion question) {
		question.setUsrAns(true);
	}

	/**
	 * Define el comportamiento cuando el usuario interactua con los componentes
	 * gráficos de una BooleanQuestion, en particular, el RadioButton que
	 * representa la respuesta "falso".
	 * 
	 * @param evt
	 *            - Evento producido por el usuario
	 * @param question
	 *            - Pregunta sobre la cual ocurre el evento.
	 */

	private void rbfalseActionPerformed(ActionEvent evt,
			BooleanQuestion question) {
		question.setUsrAns(false);
	}

	/**
	 * Renderea una pregunta de tipo SimpleQuestion en pantalla y establece su
	 * comportamiento e interacción con el usuario
	 * 
	 * @param question
	 *            - pregunta de texto timple.
	 */

	public void visit(final SimpleQuestion question) {
		final JTextField anstext = new JTextField(
				"Escriba aqui su respuesta...");
		anstext.selectAll();

		anstext.setActionCommand("respuesta");
		anstext.setToolTipText("Escriba en formato texto");

		/**
		 * Registra un manejador de eventos para el cuadro de texto donde el
		 * usuario ingresa la respuesta
		 */
		anstext.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				anstextActionPerformed(evt, question, anstext.getText());
			}
		});

		// Limpia el texto al hacer click sobre la TextField
		anstext.addMouseListener(this.clickAndClean());

		jpanel.add(anstext);
		jpanel.validate();
	}

	/**
	 * Establece la respuesta provista por el usuario en la TextField, al
	 * presionar la teclar "enter" sobre el mismo
	 * 
	 * @param evt
	 *            - Evento producido por el usuario
	 * @param question
	 *            - Pregunta sobre la cual se produce el evento
	 * @param ans
	 *            - Respuesta del usuario (Obtenida en la TextField)
	 */
	private void anstextActionPerformed(ActionEvent evt,
			SimpleQuestion question, String ans) {
		question.setUsrAns(ans);
	}

	// Se usa para limpiar el JtexField cuando se hace click.
	private MouseAdapter clickAndClean() {
		return new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				JTextField src = ((JTextField) e.getSource());
				String aux = src.getText();
				if (aux.equals("Escriba aqui su respuesta...")) {
					src.setText("");
				}
			}
		};
	}

	/**
	 * Renderea una pregunta de tipo NumericQuestion en pantalla y establece su
	 * comportamiento e interacción con el usuario
	 * 
	 * @param question
	 *            - pregunta numérica.
	 */

	public void visit(final NumericQuestion question) {
		final JTextField ansnum = new JTextField("Escriba aqui su respuesta...");

		ansnum.setActionCommand("respuesta");
		ansnum.setToolTipText("Escriba un numero");
		ansnum.selectAll();
		/**
		 * Registra un manejador de eventos para el cuadro de texto donde el
		 * usuario ingresa la respuesta
		 */
		ansnum.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				ansnumActionPerformed(evt, question, ansnum.getText());
			}
		});

		ansnum.addMouseListener(this.clickAndClean());

		jpanel.add(ansnum);
		jpanel.validate();
	}

	/**
	 * Establece la respuesta provista por el usuario en la TextField, al
	 * presionar la teclar "enter" sobre el mismo
	 * 
	 * @param evt
	 *            - Evento producido por el usuario
	 * @param question
	 *            - Pregunta sobre la cual se produce el evento
	 * @param ans
	 *            - Respuesta del usuario (Obtenida en la TextField)
	 */

	private void ansnumActionPerformed(ActionEvent evt,
			NumericQuestion question, String ans) {
		try {
			question.setUsrAns(Double.valueOf(ans));
		} catch (NumberFormatException nfe) {
			question.setUsrAns(null);
		}

	}
}
